use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::{Condvar, Mutex};

use lazy_static::lazy_static;

use crate::thread_safe_ptr;
use crate::utils::ThreadSafePtr;

///创建一个多线程控制工具
pub struct SimpleCountDownLatch {
    latch: AtomicUsize,
    inner_lock: Option<Mutex<()>>,
    inner_cond: Option<Condvar>,
}
lazy_static! {
    static ref COUNTER: AtomicUsize = AtomicUsize::new(0);
    pub static ref COUNTER_PTR: ThreadSafePtr<AtomicUsize> = ThreadSafePtr::capture(&COUNTER);
}
// unsafe impl Send for SimpleCountDownLatch {}
// unsafe impl Sync for SimpleCountDownLatch {}

impl SimpleCountDownLatch {
    pub fn new(latch: usize) -> Self {
        Self {
            latch: AtomicUsize::new(latch),
            inner_cond: None,
            inner_lock: None,
        }
    }

    pub fn new_with_lock(latch: usize) -> Self {
        Self {
            latch: AtomicUsize::new(latch),
            inner_cond: Some(Condvar::new()),
            inner_lock: Some(Mutex::new(())),
        }
    }

    pub fn count_down(&mut self) {
        self.latch.fetch_sub(1, Ordering::SeqCst);
        if let Some(cond) = self.inner_cond.as_ref() {
            cond.notify_one();
        };
    }
    fn judge_zero_and(counter: &AtomicUsize, mut fail_func: impl FnMut() -> () + Send + Sync) {
        while counter.load(Ordering::Acquire) > 0 {
            fail_func();
        }
    }
    pub fn wait(&self) {
        if let Some(lock) = &self.inner_lock {
            thread_safe_ptr! {
                let guard = Some(lock.lock().unwrap());
            }
            SimpleCountDownLatch::judge_zero_and(&self.latch, || {
                guard.read_write_ops(|tmp|{
                    Some(self.inner_cond.as_ref().unwrap().wait(tmp).unwrap())
                });
            });
        } else {
            SimpleCountDownLatch::judge_zero_and(&self.latch, || {});
        }
    }
}
